package com.spring.sd;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.DefaultSingletonBeanRegistry;
import org.springframework.boot.SpringApplication;
import org.springframework.context.ConfigurableApplicationContext;

import java.lang.reflect.Field;
import java.util.Map;

/**
 * 获取容器中的bean
 */
@Slf4j
//@SpringBootApplication
public class GetSingletonObjects {
    public static void main(String[] args) throws Exception {

        // ConfigurableApplicationContext 接口继承了 ApplicationContext 接口，
        // 而 ApplicationContext 接口又间接地继承了 BeanFactory 接口，
        // 除此之外还继承了其他很多接口，相当于对 BeanFactory 进行了拓展。
        ConfigurableApplicationContext context = SpringApplication.run(GetSingletonObjects.class, args);
        log.info("start success");

        // 通过反射获取DefaultSingletonBeanRegistry中的一级缓存中存储的bean信息
        Field singletonObjects = DefaultSingletonBeanRegistry.class.getDeclaredField("singletonObjects"); // 反射拿到这个成员变量
        // 这个singletonObjects成员变量是私有的。private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
        // 设置访问权限
        singletonObjects.setAccessible(true);

        ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();

        // 通过DefaultSingletonBeanRegistry对象实列拿到值，也就是ConfigurableListableBeanFactory继承了DefaultSingletonBeanRegistry
        Map<String, Object> map = (Map<String, Object>) singletonObjects.get(beanFactory);
        map.entrySet().stream().filter(e -> e.getKey().startsWith("component"))
                .forEach(e -> System.out.println(e.getKey() + "=" + e.getValue()));

        context.close();
    }

}
